package pluginUtils;

public class limComplexe {


private double real,im,module,argument;
	
	public static final limComplexe ZERO=createComplexeFromRI(0,0);
	public static final limComplexe INFINITY=createComplexeFromRI(Double.POSITIVE_INFINITY,0); 
	
	public static limComplexe createComplexeFromRI(double r,double i){
		double mo=Math.sqrt(r*r+i*i); 
		double ar=Math.atan2(i,r); 	
		return new limComplexe(r,i,mo,ar); 
	}
	
	public static limComplexe createComplexeFromPolar(double m,double a){
		double r=m*Math.cos(a); 
		double i=m*Math.sin(a); 
		return new limComplexe(r,i,m,a);
	}
	
	private limComplexe(double real, double im, double module, double argument) {
		//super();
		this.real = real;
		this.im = im;
		this.module = module;
		this.argument = argument;
	}
	
	public limComplexe(limComplexe source){
		this.real=source.real; 
		this.im=source.im; 
		this. module=source.module; 
		this.argument=source.argument; 
	}
	
	public static limComplexe add(limComplexe z1,limComplexe z2){
		double r,i; 
		r=z1.real+z2.real; 
		i=z1.im+z2.im; 
		return createComplexeFromRI(r,i); 
	}
	
	public static limComplexe sub(limComplexe z1,limComplexe z2){
		double r,i; 
		r=z1.real-z2.real; 
		i=z1.im-z2.im; 
		return createComplexeFromRI(r,i); 
	}
	
	public static limComplexe mul(limComplexe z1,limComplexe z2){
		double r=z1.real*z2.real-z1.im*z2.im; 
		double i=z1.im*z2.real+z2.im*z1.real; 
		return createComplexeFromRI(r, i); 
	}
	
	public static limComplexe opp(limComplexe z1){
		return createComplexeFromRI(-z1.getReal(),-z1.getIm()); 
	}
	
	public static limComplexe recip(limComplexe z){
		return mulbyDouble(z.conj(), 1/z.squareNorm());
		
	}
	
	public static limComplexe div(limComplexe z1,limComplexe z2){
		double r=z1.real*z2.real+z1.im*z2.im; 
		double i=z1.im*z2.real-z2.im*z1.real;
		double ratio=z2.squareNorm();
		return createComplexeFromRI(r/ratio, i/ratio); 
	}

	public double squareNorm(){
		return this.real*this.real+this.im*this.im;
}
	public static limComplexe mulbyDouble(limComplexe z,double x){
		return createComplexeFromRI(z.real*x,z.im*x);
	}
	
	
	public limComplexe conj(){
		return createComplexeFromRI(this.real, -this.im);
	}
	
	public limComplexe cx_sqrt(){
		if((this.real==0.0)&&(this.im==0.0)) return new limComplexe(this); 
		if(this.real>Math.abs(this.im)){
			double x=Math.sqrt(0.5*(this.real+Math.sqrt(this.squareNorm()))); 
			double y=this.im/(2*x); 
			return createComplexeFromRI(x,y);
		}
		else{
			double y=Math.sqrt(0.5*(-this.real+Math.sqrt(this.squareNorm()))); 
			double x=this.im/(2*y); 
			return createComplexeFromRI(x,y);
		}
	}
	
	public limComplexe contsqrt(limComplexe w){
		limComplexe t=this.cx_sqrt();
		if(0>t.real*w.real+t.im*w.im){
		t.real=-t.real; 
		t.im=-t.im;
		}
		return t; 
	}
	
	public double abs(){
		return Math.sqrt(this.squareNorm()); 
	}
	
	public double infNorm(){
		double a=Math.abs(this.real); 
		double b=Math.abs(this.im); 
		return Math.max(a,b); 
	}
	
	public double arg(){
		return Math.atan2(this.im,this.real); 
	}
	
	
	public limComplexe exp(){
		double x=Math.exp(this.real); 
		return createComplexeFromRI(x*Math.cos(this.im),x*Math.sin(this.im)); 
	}
	
	
	public limComplexe log(){
		double x=Math.log(this.abs()); 
		double y=this.arg(); 
		return createComplexeFromRI(x,y);
	}
	
	public limComplexe sin(){
		return createComplexeFromRI(Math.sin(this.real)*Math.cosh(this.im),Math.cos(this.real)*Math.sinh(this.im)); 
	}
	
	public limComplexe cos(){
		return createComplexeFromRI(Math.cos(this.real)*Math.cosh(this.im),-Math.sin(this.real)*Math.sinh(this.im)); 
	}
	
	public limComplexe sinh(){
		return createComplexeFromRI(Math.sinh(this.real)*Math.cos(this.im),Math.cosh(this.real)*Math.sin(this.im)); 
	}
	
	
	public limComplexe cosh(){
		return createComplexeFromRI(Math.cosh(this.real)*Math.cos(this.im),Math.sinh(this.real)*Math.sin(this.im)); 
	}
	
	public limComplexe power(double t){
		return createComplexeFromPolar(Math.pow(this.abs(),t),t*this.arg()); 
	}
	
	public limComplexe diskToSphere(){
		double s=this.abs(); 
		if(s==0) return new limComplexe(this); 
		double r=(1-Math.sqrt(1-s*s))/s; 
		return createComplexeFromRI(r/s*this.real,r/s*this.im); 
	}
	
	
	
	/**
	 * @return the real
	 */
	public double getReal() {
		return real;
	}

	/**
	 * @param real the real to set
	 */
	public void setReal(double real) {
		this.real = real;
	}

	/**
	 * @return the im
	 */
	public double getIm() {
		return im;
	}

	/**
	 * @param im the im to set
	 */
	public void setIm(double im) {
		this.im = im;
	}

	/**
	 * @return the module
	 */
	public double getModule() {
		return module;
	}

	/**
	 * @param module the module to set
	 */
	public void setModule(double module) {
		this.module = module;
	}

	/**
	 * @return the argument
	 */
	public double getArgument() {
		return argument;
	}

	/**
	 * @param argument the argument to set
	 */
	public void setArgument(double argument) {
		this.argument = argument;
	}
	
	public String toString(){
		return "("+real+","+im+")"; 
}

}
